package com.zwg.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.zwg.tingshu.album.mapper.*;
import com.zwg.tingshu.album.mapper.*;
import com.zwg.tingshu.album.service.AlbumInfoService;
import com.zwg.tingshu.common.cache.GuiGuCache;
import com.zwg.tingshu.common.constant.RedisConstant;
import com.zwg.tingshu.common.constant.RocketMqConstant;
import com.zwg.tingshu.common.constant.SystemConstant;
import com.zwg.tingshu.common.execption.GuiguException;
import com.zwg.tingshu.common.service.RocketMqService;
import com.zwg.tingshu.model.album.AlbumAttributeValue;
import com.zwg.tingshu.model.album.AlbumInfo;
import com.zwg.tingshu.model.album.AlbumStat;
import com.zwg.tingshu.model.album.TrackInfo;
import com.zwg.tingshu.query.album.AlbumInfoQuery;
import com.zwg.tingshu.vo.album.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zwg.tingshu.vo.album.*;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

	@Autowired
	private AlbumInfoMapper albumInfoMapper;
	@Autowired
	private AlbumAttributeValueMapper albumAttributeValueMapper;
	@Autowired
	private AlbumStatMapper albumStatMapper;
	@Autowired
	private TrackInfoMapper trackInfoMapper;
	@Autowired
	private RocketMqService rocketMqService;
	@Autowired
	private TrackStatMapper trackStatMapper;
	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private RedissonClient redissonClient;

	/**
	 * MQ监听更新声音统计信息（包含：播放、收藏、点赞、评论）
	 *
	 * @param mqVo
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateTrackStat(TrackStatMqVo mqVo) {
		//1.做幂等性处理，统一个消息只处理一次 采用set k(业务消息唯一标识) v NX EX
		String key = "mq:" + mqVo.getBusinessNo();
		try {
			Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, mqVo.getBusinessNo(), 1, TimeUnit.HOURS);
			if (flag) {
				//2.更新声音统计信息
				trackStatMapper.updateStat(mqVo.getTrackId(), mqVo.getStatType(), mqVo.getCount());
				//3.更新专辑统计信息(播放量、评论量只要声音+1，对应专辑也得+1)
				if (SystemConstant.TRACK_STAT_PLAY.equals(mqVo.getStatType())) {
					albumStatMapper.updateStat(mqVo.getAlbumId(), SystemConstant.ALBUM_STAT_PLAY, mqVo.getCount());
				}
				if (SystemConstant.TRACK_STAT_COMMENT.equals(mqVo.getStatType())) {
					albumStatMapper.updateStat(mqVo.getAlbumId(), SystemConstant.ALBUM_STAT_COMMENT, mqVo.getCount());
				}
			}
		} catch (Exception e) {
			//如果更新数据库发送异常，事务会进行回滚，下次再次投递消息允许继续处理统一个消息
			redisTemplate.delete(key);
			throw new RuntimeException(e);
		}
	}


	/**
	 * 根据专辑ID查询专辑统计信息
	 *
	 * @param albumId
	 * @return
	 */
	@Override
	public AlbumStatVo getAlbumStatVo(Long albumId) {
		return albumInfoMapper.getAlbumStatVo(albumId);
	}

	/**
	 * 保存专辑方法
	 * 1.将提交专辑VO转为PO对象，新增专辑
	 * 2.将提交专辑标签封装为专辑标签关系集合对象，进行批量保存
	 * 3.为新增专辑标签，批量保存专辑统计信息
	 *
	 * @param userId 用户ID
	 * @param albumInfoVo 专辑信息VO对象
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveAlbumInfo(Long userId, AlbumInfoVo albumInfoVo) {
		//1.保存专辑
		//1.1 将提交专辑VO拷贝到专辑PO对象中 仅限同名同类型属性才会被拷贝
		AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
		//1.2 手动为用户id、包含声音数量（0）、是否完结、免费试听集数、审核状态（TODO：审核通过，实则有内容审核机制）
		albumInfo.setUserId(userId);
		albumInfo.setIncludeTrackCount(0);
		albumInfo.setIsFinished("0");
		albumInfo.setTracksForFree(5);
		albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
		//1.3 保存专辑，得到专辑ID
		albumInfoMapper.insert(albumInfo);
		Long albumId = albumInfo.getId();

		//2.保存专辑标签关系
		//2.1 将提交专辑标签关系VO集合转为PO集合
		List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
		if (CollectionUtil.isNotEmpty(albumAttributeValueVoList)) {
			//2.2 关联专辑ID批量保存专辑标签关系
			for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
				AlbumAttributeValue albumAttributeValue = BeanUtil.copyProperties(albumAttributeValueVo, AlbumAttributeValue.class);
				albumAttributeValue.setAlbumId(albumId);
				albumAttributeValueMapper.insert(albumAttributeValue);
			}
		}

		//3.保存专辑统计信息（4条）
		this.saveAlbumStat(albumId, SystemConstant.ALBUM_STAT_PLAY, 0);
		this.saveAlbumStat(albumId, SystemConstant.ALBUM_STAT_SUBSCRIBE, 0);
		this.saveAlbumStat(albumId, SystemConstant.ALBUM_STAT_BUY, 0);
		this.saveAlbumStat(albumId, SystemConstant.ALBUM_STAT_COMMENT, 0);

		//4.TODO 调用内容审核接口（第三方阿里云）对专辑内容（封面、文字

		//5.审核通过后发送上架专辑消息到rocketmq
		if ("1".equals(albumInfo.getIsOpen())) {
			rocketMqService.sendAsync(RocketMqConstant.QUEUE_ALBUM_UPPER,RocketMqConstant.QUEUE_ALBUM_UPPER,albumId.toString());
		}
	}

	/**
	 * 保存专辑统计信息
	 * @param albumId 专辑ID
	 * @param statType 统计类型
	 * @param statNum 统计数量
	 */
	@Override
	public void saveAlbumStat(Long albumId, String statType, int statNum) {
		AlbumStat albumStat = new AlbumStat();
		albumStat.setAlbumId(albumId);
		albumStat.setStatType(statType);
		albumStat.setStatNum(statNum);
		albumStatMapper.insert(albumStat);
	}


	/**
	 *  获取用户专辑分页数据
	 * @param pageInfo 分页对象
	 * @param albumInfoQuery 专辑查询条件
	 * @return
	 */
	@Override
	public Page<AlbumListVo> getUserAlbumPage(Page<AlbumListVo> pageInfo, AlbumInfoQuery albumInfoQuery) {
		return albumInfoMapper.getUserAlbumPage(pageInfo, albumInfoQuery);
	}

	/**
	 * 删除专辑
	 * @param id 专辑ID
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeAlbumInfo(Long id) {
		//1.根据专辑ID查询该专辑下包含声音 如果关联声音则不允许删除（必须先删除声音）
		LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(TrackInfo::getAlbumId, id);
		Long count = trackInfoMapper.selectCount(queryWrapper);
		if (count > 0) {
			throw new GuiguException(400, "该专辑下存在未删除声音！");
		}
		//2.根据主键删除专辑
		albumInfoMapper.deleteById(id);
		//3.根据专辑ID删除专辑属性标签
		LambdaQueryWrapper<AlbumAttributeValue> albumAttributeValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
		albumAttributeValueLambdaQueryWrapper.eq(AlbumAttributeValue::getAlbumId, id);
		albumAttributeValueMapper.delete(albumAttributeValueLambdaQueryWrapper);
		//4.根据专辑ID删除专辑统计数据
		LambdaQueryWrapper<AlbumStat> albumStatLambdaQueryWrapper = new LambdaQueryWrapper<>();
		albumStatLambdaQueryWrapper.eq(AlbumStat::getAlbumId, id);
		albumStatMapper.delete(albumStatLambdaQueryWrapper);

		// 同步删除索引库中专辑文档
		rocketMqService.sendAsync(RocketMqConstant.QUEUE_ALBUM_LOWER,RocketMqConstant.QUEUE_ALBUM_LOWER,id.toString());
	}

	/**
	 * 根据专辑ID查询专辑信息（包含专辑标签及值）
	 *
	 * @param id
	 * @return
	 */
	@Override
	@GuiGuCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
	public AlbumInfo getAlbumInfo(Long id) {
		//1.根据专辑ID主键查询专辑信息
		AlbumInfo albumInfo = albumInfoMapper.selectById(id);
		//2.根据专辑ID查询标签列表
		if (albumInfo != null) {
			LambdaQueryWrapper<AlbumAttributeValue> queryWrapper = new LambdaQueryWrapper<>();
			queryWrapper.eq(AlbumAttributeValue::getAlbumId, id);
			List<AlbumAttributeValue> attributeValueList = albumAttributeValueMapper.selectList(queryWrapper);
			albumInfo.setAlbumAttributeValueVoList(attributeValueList);
		}
		return albumInfo;
	}

	/**
	 * 修改专辑信息
	 *
	 * @param id 专辑ID
	 * @param albumInfoVo 修改专辑信息VO对象
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo) {
		//1.修改专辑信息
		//2.1 将修改专辑信息转为PO对象 封装专辑ID
		AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
		albumInfo.setId(id);
		//2.2 修改专辑
		albumInfoMapper.updateById(albumInfo);
		//2.修改专辑标签 先删再新增
		//2.1 根据专辑ID将以前关联标签记录全部删除
		LambdaQueryWrapper<AlbumAttributeValue> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(AlbumAttributeValue::getAlbumId, id);
		albumAttributeValueMapper.delete(queryWrapper);
		//2.2 在根据提交专辑标签做新增
		List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
		if (CollectionUtil.isNotEmpty(albumAttributeValueVoList)) {
			//2.2 关联专辑ID批量保存专辑标签关系
			for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
				AlbumAttributeValue albumAttributeValue = BeanUtil.copyProperties(albumAttributeValueVo, AlbumAttributeValue.class);
				albumAttributeValue.setAlbumId(id);
				albumAttributeValueMapper.insert(albumAttributeValue);
			}
		}
		// 如果是开放专辑自动将专辑同步到ES索引库中
		if ("1".equals(albumInfo.getIsOpen())) {
			rocketMqService.sendAsync(RocketMqConstant.QUEUE_ALBUM_UPPER,RocketMqConstant.QUEUE_ALBUM_UPPER, albumInfo.getId().toString());
		} else {
			rocketMqService.sendAsync(RocketMqConstant.QUEUE_ALBUM_LOWER,RocketMqConstant.QUEUE_ALBUM_LOWER, albumInfo.getId().toString());

		}
	}

	/**
	 * 查询当指定用户专辑列表
	 * @param userId
	 * @return
	 */
	@Override
	public List<AlbumInfo> getUserAllAlbumList(Long userId) {
		//1.创建条件构造器封装查询条件
		LambdaQueryWrapper<AlbumInfo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(AlbumInfo::getUserId, userId);
		//2.指定查询字段 select 后面列名称
		queryWrapper.select(AlbumInfo::getId, AlbumInfo::getAlbumTitle, AlbumInfo::getStatus);
		//3.TODO 避免小程序响应1千多条记录导致卡顿 需要指定加载数量 limit 200
		queryWrapper.last("limit 200");
		//4.设置排序按照最新专辑
		queryWrapper.orderByDesc(AlbumInfo::getId);
		return albumInfoMapper.selectList(queryWrapper);
	}
}
